package com.example.yuanboot.common.config.validator;

import com.example.yuanboot.common.exception.BaseException;
import com.example.yuanboot.common.msg.ObjectRestResponse;
import com.example.yuanboot.common.msg.ResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Objects;

/**
 * 全局异常拦截器
 *
 * @author qingyan 2021-07-05
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(value = BaseException.class)
    public ObjectRestResponse<String> exceptionHandler(BaseException e){
        log.error("code:{}, message:{}", e.getStatus(), e.getMessage());
        return ResponseUtils.f(Integer.toString(e.getStatus()), e.getMessage());
    }
    /**
     * 全局异常捕获BindException、MethodArgumentNotValidException和ConstraintViolationException
     * BindException（@Validated @Valid仅对于表单提交有效，对于以json格式提交将会失效)
     * MethodArgumentNotValidException（@Validated @Valid 前端提交的方式为json格式有效，出现异常时会被该异常类处理）
     * ConstraintViolationException  验证controller层使用requestparam和pathvariable下的参数
     *
     */
    @ExceptionHandler(value = BindException.class)
    public ObjectRestResponse<String> exceptionHandler(BindException e){
        log.error("code:{}, message:{}", "500", e.getMessage());
        return ResponseUtils.f("500", e.getAllErrors().get(0).getDefaultMessage());
    }


    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ObjectRestResponse<String> exceptionHandler(MethodArgumentNotValidException e){
        log.error("code:{}, message:{}", "500", e.getMessage());
        String defaultMessage = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
        return ResponseUtils.f("500", defaultMessage);
    }

    @ExceptionHandler(value = ConstraintViolationException.class)
    public ObjectRestResponse<String> exceptionHandler(ConstraintViolationException e){
        String message = e.getConstraintViolations().stream().findFirst().map(ConstraintViolation::getMessage).orElse("");
        log.error("code:{}, message:{}", "500", message);
        return ResponseUtils.f("500", message);
    }
    
    @ExceptionHandler(value = Exception.class)
    public ObjectRestResponse<String> exceptionHandler(Exception e){
        log.error("code:{}, message:{}", "500", e);
        return ResponseUtils.f("500", "服务异常");
    }
}
